"""Configuration management for Auto Review tool."""

import os
import re
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, List, Optional

import yaml
from dotenv import load_dotenv


@dataclass
class RepositoryConfig:
    """Repository configuration."""

    name: str
    priority: int
    max_review_per_day: int
    enabled: bool
    ssh_url: str
    local_path: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "RepositoryConfig":
        """Create RepositoryConfig from dictionary."""
        return cls(
            name=data["name"],
            priority=data.get("priority", 999),
            max_review_per_day=data.get("max_review_per_day", 10),
            enabled=data.get("enabled", True),
            ssh_url=data["ssh_url"],
            local_path=data["local_path"],
        )


@dataclass
class LLMConfig:
    """LLM configuration."""

    provider: str
    api_key: str
    base_url: str
    model: str
    temperature: float
    max_tokens: int

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "LLMConfig":
        """Create LLMConfig from dictionary."""
        return cls(
            provider=data.get("provider", "dashscope"),
            api_key=cls._resolve_env_var(data["api_key"]),
            base_url=data.get("base_url", ""),
            model=data.get("model", "qwen-plus"),
            temperature=data.get("temperature", 0.3),
            max_tokens=data.get("max_tokens", 4000),
        )

    @staticmethod
    def _resolve_env_var(value: str) -> str:
        """Resolve environment variable in config value."""
        if value.startswith("${") and value.endswith("}"):
            env_var = value[2:-1]
            return os.getenv(env_var, "")
        return value


@dataclass
class EmailConfig:
    """Email configuration."""

    smtp_server: str
    smtp_port: int
    smtp_user: str
    smtp_password: str
    from_address: str
    to_addresses: List[str]

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "EmailConfig":
        """Create EmailConfig from dictionary."""
        return cls(
            smtp_server=data["smtp_server"],
            smtp_port=data.get("smtp_port", 587),
            smtp_user=cls._resolve_env_var(data["smtp_user"]),
            smtp_password=cls._resolve_env_var(data["smtp_password"]),
            from_address=data["from_address"],
            to_addresses=data["to_addresses"],
        )

    @staticmethod
    def _resolve_env_var(value: str) -> str:
        """Resolve environment variable in config value."""
        if value.startswith("${") and value.endswith("}"):
            env_var = value[2:-1]
            return os.getenv(env_var, "")
        return value


class ConfigManager:
    """Configuration manager for Auto Review tool."""

    def __init__(self, config_path: Optional[str] = None):
        """
        Initialize configuration manager.

        Args:
            config_path: Path to configuration file. Defaults to 'config.yaml' in current directory.
        """
        if config_path is None:
            config_path = os.path.join(os.getcwd(), "config.yaml")

        self.config_path = Path(config_path)
        self._config: Dict[str, Any] = {}
        self._load_config()

    def _load_config(self) -> None:
        """Load configuration from YAML file."""
        if not self.config_path.exists():
            raise FileNotFoundError(f"Configuration file not found: {self.config_path}")

        # Load environment variables
        load_dotenv()

        with open(self.config_path, "r", encoding="utf-8") as f:
            raw_config = yaml.safe_load(f)

        # Resolve environment variables in config
        self._config = self._resolve_env_vars(raw_config)

    def _resolve_env_vars(self, config: Any) -> Any:
        """
        Recursively resolve environment variables in configuration.

        Args:
            config: Configuration dictionary or value

        Returns:
            Configuration with environment variables resolved
        """
        if isinstance(config, dict):
            return {k: self._resolve_env_vars(v) for k, v in config.items()}
        elif isinstance(config, list):
            return [self._resolve_env_vars(item) for item in config]
        elif isinstance(config, str):
            # Match ${VAR_NAME} pattern
            pattern = r"\$\{([^}]+)\}"
            matches = re.findall(pattern, config)
            if matches:
                for var_name in matches:
                    env_value = os.getenv(var_name, "")
                    config = config.replace(f"${{{var_name}}}", env_value)
            return config
        else:
            return config

    def get_repositories(self) -> List[RepositoryConfig]:
        """
        Get list of repository configurations.

        Returns:
            List of RepositoryConfig objects, sorted by priority
        """
        repos_data = self._config.get("repositories", [])
        repos = [RepositoryConfig.from_dict(repo) for repo in repos_data if repo.get("enabled", True)]
        return sorted(repos, key=lambda x: x.priority)

    def get_llm_config(self) -> LLMConfig:
        """
        Get LLM configuration.

        Returns:
            LLMConfig object
        """
        llm_data = self._config.get("llm", {})
        return LLMConfig.from_dict(llm_data)

    def get_email_config(self) -> EmailConfig:
        """
        Get email configuration.

        Returns:
            EmailConfig object
        """
        email_data = self._config.get("email", {})
        return EmailConfig.from_dict(email_data)

    def get_gitcode_config(self) -> Dict[str, str]:
        """
        Get GitCode API configuration.

        Returns:
            Dictionary with api_base_url and access_token
        """
        gitcode_data = self._config.get("gitcode", {})
        access_token = self._resolve_env_vars(gitcode_data.get("access_token", ""))
        return {
            "api_base_url": gitcode_data.get("api_base_url", "https://api.gitcode.com"),
            "access_token": access_token,
        }

    def get_schedule_config(self) -> Dict[str, Any]:
        """
        Get schedule configuration.

        Returns:
            Dictionary with schedule settings
        """
        return self._config.get("schedule", {})

    def get_review_config(self) -> Dict[str, Any]:
        """
        Get review configuration.

        Returns:
            Dictionary with review settings
        """
        return self._config.get("review", {})

    def get_database_config(self) -> Dict[str, Any]:
        """
        Get database configuration.

        Returns:
            Dictionary with database settings
        """
        return self._config.get("database", {})

    def get_logging_config(self) -> Dict[str, Any]:
        """
        Get logging configuration.

        Returns:
            Dictionary with logging settings
        """
        return self._config.get("logging", {})

    def validate_config(self) -> bool:
        """
        Validate configuration.

        Returns:
            True if configuration is valid

        Raises:
            ValueError: If configuration is invalid
        """
        errors = []

        # Validate GitCode config
        gitcode_config = self.get_gitcode_config()
        if not gitcode_config.get("access_token"):
            errors.append("GitCode access_token is required")

        # Validate LLM config
        llm_config = self.get_llm_config()
        if not llm_config.api_key:
            errors.append("LLM api_key is required")

        # Validate repositories
        repos = self.get_repositories()
        if not repos:
            errors.append("At least one enabled repository is required")

        # Validate email config (if schedule is enabled)
        schedule_config = self.get_schedule_config()
        if schedule_config.get("enabled", True):
            email_config = self.get_email_config()
            if not email_config.smtp_server:
                errors.append("Email smtp_server is required when schedule is enabled")
            if not email_config.to_addresses:
                errors.append("Email to_addresses is required when schedule is enabled")

        if errors:
            raise ValueError("Configuration validation failed:\n" + "\n".join(f"  - {e}" for e in errors))

        return True

    def get_config(self) -> Dict[str, Any]:
        """
        Get full configuration dictionary.

        Returns:
            Complete configuration dictionary
        """
        return self._config.copy()

